use crate::{
    ast::{
        stmt, types, BinaryExpr, BinaryOp, CallExpr, Expression, Literal, MethodCallExpr, Pattern,
        Statement, Type, UnaryExpr, UnaryOp,
    },
    error::{CompilerError, Result},
    llvm_backend::LLVMBackend,
};
use inkwell::{
    values::{BasicMetadataValueEnum, BasicValueEnum},
    AddressSpace,
};

impl<'ctx> LLVMBackend<'ctx> {
    /// Add built-in functions to the module
    pub(super) fn add_builtin_functions(&mut self) -> Result<()> {
        // 声明外部函数，不实现函数体
        let i8_ptr_type = self.context.i8_type().ptr_type(AddressSpace::default());

        // 声明 printf 函数
        let printf_type = self.context.i32_type().fn_type(&[i8_ptr_type.into()], true);
        let printf_func = self.module.add_function("printf", printf_type, None);
        self.function_map.insert("printf".to_string(), printf_func);

        // 声明 putchar 函数
        let putchar_type = self
            .context
            .i32_type()
            .fn_type(&[self.context.i32_type().into()], false);
        let _putchar_func = self.module.add_function("putchar", putchar_type, None);

        // 声明 println 函数（可变参数）
        let println_type = self
            .context
            .void_type()
            .fn_type(&[i8_ptr_type.into()], true);
        let println_func = self.module.add_function("println", println_type, None);
        self.function_map
            .insert("println".to_string(), println_func);

        // 声明 print 函数（可变参数）
        let print_func = self.module.add_function("print", println_type, None);
        self.function_map.insert("print".to_string(), print_func);

        // 声明 exit 函数（C标准库，用于assert）
        let exit_type = self
            .context
            .void_type()
            .fn_type(&[self.context.i32_type().into()], false);
        let _exit_func = self.module.add_function("exit", exit_type, None);

        // 声明 len 函数（作为外部函数，使用C标准库的strlen）
        let len_type = self
            .context
            .i32_type()
            .fn_type(&[i8_ptr_type.into()], false);
        let len_func = self.module.add_function("strlen", len_type, None);
        self.function_map.insert("len".to_string(), len_func);
        self.function_map.insert("strlen".to_string(), len_func);

        // 声明 strcmp 函数（用于字符串比较）
        let strcmp_type = self
            .context
            .i32_type()
            .fn_type(&[i8_ptr_type.into(), i8_ptr_type.into()], false);
        let strcmp_func = self.module.add_function("strcmp", strcmp_type, None);
        self.function_map.insert("strcmp".to_string(), strcmp_func);

        // 声明 memmove 函数（用于移动内存，支持重叠区域）
        let memmove_type = i8_ptr_type.fn_type(
            &[
                i8_ptr_type.into(),
                i8_ptr_type.into(),
                self.context.i64_type().into(),
            ],
            false,
        );
        let memmove_func = self.module.add_function("memmove", memmove_type, None);
        self.function_map
            .insert("memmove".to_string(), memmove_func);

        // 声明手动内存管理函数
        let i8_ptr_type = self.context.i8_type().ptr_type(AddressSpace::default());

        // malloc: C标准库的内存分配函数
        let malloc_type = self
            .context
            .i8_type()
            .ptr_type(AddressSpace::default())
            .fn_type(&[self.context.i64_type().into()], false);
        let malloc_func = self.module.add_function("malloc", malloc_type, None);
        self.function_map.insert("malloc".to_string(), malloc_func);
        self.function_map
            .insert("__malloc".to_string(), malloc_func); // Keep __malloc as alias

        // __free: 释放内存
        let free_type = self
            .context
            .void_type()
            .fn_type(&[i8_ptr_type.into(), self.context.i64_type().into()], false);
        let free_func = self.module.add_function("__free", free_type, None);
        self.function_map.insert("__free".to_string(), free_func);

        // __realloc: 重新分配内存
        let realloc_type = self
            .context
            .i8_type()
            .ptr_type(AddressSpace::default())
            .fn_type(
                &[
                    i8_ptr_type.into(),
                    self.context.i64_type().into(),
                    self.context.i64_type().into(),
                ],
                false,
            );
        let realloc_func = self.module.add_function("__realloc", realloc_type, None);
        self.function_map
            .insert("__realloc".to_string(), realloc_func);

        // free: C标准库的内存释放函数
        let free_type = self
            .context
            .void_type()
            .fn_type(&[i8_ptr_type.into()], false);
        let free_func = self.module.add_function("free", free_type, None);
        self.function_map.insert("free".to_string(), free_func);

        // 声明 assert 函数
        let assert_type = self.context.void_type().fn_type(
            &[self.context.bool_type().into(), i8_ptr_type.into()],
            false,
        );
        let _assert_func = self.module.add_function("assert", assert_type, None);

        // 引用计数现在通过内联LLVM IR实现，不需要外部函数声明

        Ok(())
    }

    /// Generate method call with a specific method name
    pub(super) fn generate_method_call_with_name(
        &mut self,
        method_call: &MethodCallExpr,
        method_name: &str,
    ) -> Result<BasicValueEnum<'ctx>> {
        // Generate the object (receiver)
        let receiver = self.generate_expression(&method_call.object)?;

        // Look up the method function
        let function = *self
            .function_map
            .get(method_name)
            .ok_or_else(|| CompilerError::internal(format!("Undefined method: {}", method_name)))?;

        // Check if the method expects a pointer type for the first parameter (self)
        let expects_pointer =
            if let Some(first_param) = function.get_type().get_param_types().first() {
                first_param.is_pointer_type()
            } else {
                false
            };

        // Generate arguments (receiver + method arguments)
        let receiver_arg: BasicMetadataValueEnum = if expects_pointer {
            // Method expects pointer type (self), pass the pointer directly
            if let Expression::Variable(var_name) = &*method_call.object {
                if let Some(var_value) = self.variable_map.get(var_name) {
                    if var_value.is_pointer_value() {
                        (*var_value).into()
                    } else {
                        return Err(CompilerError::internal(
                            "Cannot get pointer of non-pointer receiver",
                        ));
                    }
                } else {
                    return Err(CompilerError::internal(format!(
                        "Undefined receiver variable: {}",
                        var_name
                    )));
                }
            } else {
                return Err(CompilerError::internal("Cannot get receiver pointer"));
            }
        } else {
            // Method expects value type (self), pass the struct value
            match receiver {
                BasicValueEnum::StructValue(_) => receiver.into(),
                _ => {
                    if let Expression::Variable(var_name) = &*method_call.object {
                        if let Some(var_value) = self.variable_map.get(var_name) {
                            if var_value.is_pointer_value() {
                                let struct_type = self.context.struct_type(
                                    &[
                                        self.context
                                            .i8_type()
                                            .ptr_type(inkwell::AddressSpace::default())
                                            .into(), // name field (string)
                                        self.context.i32_type().into(), // age field (int)
                                    ],
                                    false,
                                );
                                let loaded_value = self.builder.build_load(
                                    struct_type,
                                    var_value.into_pointer_value(),
                                    "loaded_receiver",
                                )?;
                                loaded_value.into()
                            } else {
                                return Err(CompilerError::internal(
                                    "Cannot get value of non-pointer receiver",
                                ));
                            }
                        } else {
                            return Err(CompilerError::internal(format!(
                                "Undefined receiver variable: {}",
                                var_name
                            )));
                        }
                    } else {
                        return Err(CompilerError::internal("Cannot get receiver value"));
                    }
                }
            }
        };

        let mut args: Vec<BasicMetadataValueEnum> = vec![receiver_arg];

        for arg in &method_call.arguments {
            let arg_value = self.generate_expression(arg)?;
            args.push(arg_value.into());
        }

        // Build the call
        let result = self.builder.build_call(function, &args, "method_call")?;

        // Handle return value
        if function.get_type().get_return_type().is_some() {
            Ok(result.try_as_basic_value().left().unwrap())
        } else {
            Ok(self.context.i32_type().const_int(0, false).into())
        }
    }

    /// Generate static method call with a specific method name (no receiver)
    pub(super) fn generate_static_method_call_with_name(
        &mut self,
        method_call: &MethodCallExpr,
        method_name: &str,
    ) -> Result<BasicValueEnum<'ctx>> {
        // Look up the method function
        let function = *self.function_map.get(method_name).ok_or_else(|| {
            CompilerError::internal(format!("Undefined static method: {}", method_name))
        })?;

        // Generate arguments (only method arguments, no receiver)
        let mut args = Vec::new();
        for arg in &method_call.arguments {
            let arg_value = self.generate_expression(arg)?;
            args.push(arg_value.into());
        }

        // Call the function
        let result = self
            .builder
            .build_call(function, &args, "static_method_call")?;

        // Return the result
        if function.get_type().get_return_type().is_some() {
            Ok(result.try_as_basic_value().left().unwrap())
        } else {
            Ok(self.context.i32_type().const_int(0, false).into())
        }
    }

    /// Generate print/println call
    pub(super) fn generate_print_call(
        &mut self,
        func_name: &str,
        arguments: &[Expression],
    ) -> Result<BasicValueEnum<'ctx>> {
        let printf_func = self
            .module
            .get_function("printf")
            .ok_or_else(|| CompilerError::internal("printf function not found"))?;
        let putchar_func = self
            .module
            .get_function("putchar")
            .ok_or_else(|| CompilerError::internal("putchar function not found"))?;

        // 处理每个参数
        for arg in arguments.iter() {
            let value = self.generate_expression(arg)?;

            // Try to infer the type from the expression
            let inferred_type = self.infer_expression_type(arg);

            match value {
                BasicValueEnum::PointerValue(ptr) => {
                    // 检查是否是字符串类型
                    // 1. 直接的字符串字面量
                    // 2. 字符串字段访问
                    // 3. 推断类型为字符串的表达式（如字符串变量、if表达式返回字符串等）
                    let is_string = self.is_string_literal(arg)
                        || self.is_string_field_access(arg)
                        || matches!(inferred_type, Some(Type::Basic(types::BasicType::String)));

                    if is_string {
                        // 字符串类型，使用 %s 格式符
                        let format_str =
                            self.builder.build_global_string_ptr("%s", "format_str")?;
                        let _call = self.builder.build_call(
                            printf_func,
                            &[format_str.as_pointer_value().into(), ptr.into()],
                            "printf_str_call",
                        );
                    } else {
                        // 真正的指针，使用 %p 格式符
                        let ptr_as_int = self.builder.build_ptr_to_int(
                            ptr,
                            self.context.i64_type(),
                            "ptr_as_int",
                        )?;
                        let format_str =
                            self.builder.build_global_string_ptr("%p", "format_str")?;
                        let _ = self.builder.build_call(
                            printf_func,
                            &[format_str.as_pointer_value().into(), ptr_as_int.into()],
                            "printf_ptr_call",
                        );
                    }
                }
                BasicValueEnum::IntValue(int_val) => {
                    // 根据推断的类型选择正确的格式符
                    let (format_str_text, cast_value) =
                        if let Some(Type::Basic(basic_type)) = inferred_type {
                            match basic_type {
                                // 无符号整数
                                types::BasicType::Uint8 => ("%hhu", int_val.into()),
                                types::BasicType::Uint16 => ("%hu", int_val.into()),
                                types::BasicType::Uint32 => ("%u", int_val.into()),
                                types::BasicType::Uint | types::BasicType::Uint64 => {
                                    ("%llu", int_val.into())
                                }
                                // 有符号整数
                                types::BasicType::Int8 => {
                                    // Sign extend to int for printf
                                    let extended = self.builder.build_int_s_extend(
                                        int_val,
                                        self.context.i32_type(),
                                        "sext",
                                    )?;
                                    ("%hhd", extended.into())
                                }
                                types::BasicType::Int16 => {
                                    let extended = self.builder.build_int_s_extend(
                                        int_val,
                                        self.context.i32_type(),
                                        "sext",
                                    )?;
                                    ("%hd", extended.into())
                                }
                                types::BasicType::Int32 => ("%d", int_val.into()),
                                types::BasicType::Int | types::BasicType::Int64 => {
                                    ("%lld", int_val.into())
                                }
                                types::BasicType::Bool => ("%d", int_val.into()),
                                _ => ("%d", int_val.into()),
                            }
                        } else {
                            // 默认使用 %d
                            ("%d", int_val.into())
                        };

                    let format_str = self
                        .builder
                        .build_global_string_ptr(format_str_text, "format_str")?;
                    let _call = self.builder.build_call(
                        printf_func,
                        &[format_str.as_pointer_value().into(), cast_value],
                        "printf_int_call",
                    );
                }
                BasicValueEnum::FloatValue(float_val) => {
                    // 浮点数参数，需要格式化字符串
                    let format_str = self.builder.build_global_string_ptr("%f", "format_str")?;
                    let _ = self.builder.build_call(
                        printf_func,
                        &[format_str.as_pointer_value().into(), float_val.into()],
                        "printf_float_call",
                    );
                }
                _ => {
                    // Check if this is a struct type - try to call to_string method if available
                    if let Some(Type::Struct(struct_type)) = inferred_type {
                        // Try to find to_string method
                        let method_name = format!("{}.to_string", struct_type.name);
                        let has_to_string = self.function_map.contains_key(&method_name);

                        if has_to_string {
                            // Generate struct value first
                            let struct_value = self.generate_expression(arg)?;

                            // Create a reference to the struct for method call
                            let struct_ptr = match struct_value {
                                BasicValueEnum::PointerValue(ptr) => ptr,
                                BasicValueEnum::StructValue(_) => {
                                    // If it's a struct value, we need to allocate it and get a pointer
                                    // For now, let's assume struct values are already pointers
                                    // This might need adjustment based on how structs are handled
                                    return Err(CompilerError::internal(
                                        "Struct value not supported in print - use pointer",
                                    ));
                                }
                                _ => {
                                    return Err(CompilerError::internal(
                                        "Unexpected struct value type in print",
                                    ))
                                }
                            };

                            // Get to_string function (now that we're done with mutable borrow)
                            let to_string_func =
                                self.function_map.get(&method_name).ok_or_else(|| {
                                    CompilerError::internal("to_string method not found")
                                })?;

                            // Call to_string method
                            let to_string_result = self.builder.build_call(
                                *to_string_func,
                                &[struct_ptr.into()],
                                "to_string_call",
                            )?;

                            // to_string returns a String, which is a pointer
                            // Extract the return value from the call result
                            if let Some(return_value) = to_string_result.try_as_basic_value().left()
                            {
                                match return_value {
                                    BasicValueEnum::PointerValue(ptr) => {
                                        // Print the string result
                                        let format_str = self
                                            .builder
                                            .build_global_string_ptr("%s", "format_str")?;
                                        let _ = self.builder.build_call(
                                            printf_func,
                                            &[format_str.as_pointer_value().into(), ptr.into()],
                                            "printf_str_call",
                                        );
                                    }
                                    _ => {
                                        return Err(CompilerError::internal(
                                            "to_string method did not return String type",
                                        ));
                                    }
                                }
                            } else {
                                return Err(CompilerError::internal(
                                    "to_string method did not return expected type",
                                ));
                            }
                        } else {
                            // No to_string method, print struct type name as fallback
                            let type_name_str = format!("{}{{...}}", struct_type.name);
                            let format_str =
                                self.builder.build_global_string_ptr("%s", "format_str")?;
                            let type_name_ptr = self
                                .builder
                                .build_global_string_ptr(&type_name_str, "type_name")?;
                            let _ = self.builder.build_call(
                                printf_func,
                                &[
                                    format_str.as_pointer_value().into(),
                                    type_name_ptr.as_pointer_value().into(),
                                ],
                                "printf_type_name",
                            );
                        }
                    } else {
                        return Err(CompilerError::internal(
                            "Unsupported argument type for print",
                        ));
                    }
                }
            }
        }

        // 如果是 println，添加换行符
        if func_name == "println" {
            let newline = self.context.i32_type().const_int('\n' as u64, false);
            let _ = self
                .builder
                .build_call(putchar_func, &[newline.into()], "putchar_call");
        }
        Ok(self.context.i32_type().const_int(0, false).into())
    }

    /// Generate assert call: assert(cond, message)
    pub(super) fn generate_assert_comparison_call(
        &mut self,
        arguments: &[Expression],
        location: crate::error::Location,
        operator: BinaryOp,
    ) -> Result<BasicValueEnum<'ctx>> {
        if arguments.len() != 3 {
            return Err(CompilerError::semantic(
                location.line,
                location.column,
                "assert_eq/assert_ne requires 3 arguments: actual, expected, message",
            ));
        }

        let comparison_expr = Expression::Binary(BinaryExpr {
            left: Box::new(arguments[0].clone()),
            operator,
            right: Box::new(arguments[1].clone()),
            location,
        });

        let mut assert_args = Vec::with_capacity(2);
        assert_args.push(comparison_expr);
        assert_args.push(arguments[2].clone());

        self.generate_assert_call(&assert_args)
    }

    pub(super) fn generate_assert_bool_call(
        &mut self,
        arguments: &[Expression],
        location: crate::error::Location,
        expect_true: bool,
    ) -> Result<BasicValueEnum<'ctx>> {
        if arguments.len() != 2 {
            return Err(CompilerError::semantic(
                location.line,
                location.column,
                "assert_true/assert_false requires 2 arguments: condition and message",
            ));
        }

        let condition_expr = if expect_true {
            arguments[0].clone()
        } else {
            Expression::Unary(UnaryExpr {
                operator: UnaryOp::Not,
                operand: Box::new(arguments[0].clone()),
                location,
            })
        };

        let mut assert_args = Vec::with_capacity(2);
        assert_args.push(condition_expr);
        assert_args.push(arguments[1].clone());

        self.generate_assert_call(&assert_args)
    }

    pub(super) fn generate_assert_panics_entry(
        &mut self,
        arguments: &[Expression],
        location: crate::error::Location,
    ) -> Result<BasicValueEnum<'ctx>> {
        if arguments.len() != 2 {
            return Err(CompilerError::semantic(
                location.line,
                location.column,
                "assert_panics requires 2 arguments: test function and message",
            ));
        }

        self.generate_assert_panics_call(&arguments[0], &arguments[1], location)
    }

    pub(super) fn generate_assert_call(
        &mut self,
        arguments: &[Expression],
    ) -> Result<BasicValueEnum<'ctx>> {
        if arguments.len() != 2 {
            return Err(CompilerError::internal(
                "assert() requires exactly 2 arguments: (cond: bool, message: String)",
            ));
        }

        // Generate condition expression
        let cond = self.generate_expression(&arguments[0])?;
        let cond_int = match cond {
            BasicValueEnum::IntValue(int_val) => int_val,
            _ => {
                return Err(CompilerError::internal(
                    "assert() condition must be a boolean",
                ))
            }
        };

        // Get functions we need
        let printf_func = self
            .module
            .get_function("printf")
            .ok_or_else(|| CompilerError::internal("printf function not found"))?;
        let exit_func = self
            .module
            .get_function("exit")
            .ok_or_else(|| CompilerError::internal("exit function not found"))?;

        // Create basic blocks for control flow
        let parent_fn = self
            .builder
            .get_insert_block()
            .and_then(|b| b.get_parent())
            .ok_or_else(|| CompilerError::internal("No parent function for assert"))?;

        let fail_block = self.context.append_basic_block(parent_fn, "assert_fail");
        let pass_block = self.context.append_basic_block(parent_fn, "assert_pass");

        // Branch based on condition (if cond == 0, go to fail_block)
        // cond_int might be i1 (bool) or i32, we need to check its type
        let cond_type = cond_int.get_type();
        let zero = cond_type.const_int(0, false);
        let is_false = self.builder.build_int_compare(
            inkwell::IntPredicate::EQ,
            cond_int,
            zero,
            "is_false",
        )?;
        let _ = self
            .builder
            .build_conditional_branch(is_false, fail_block, pass_block);

        // Generate fail block
        self.builder.position_at_end(fail_block);

        // Print "Assertion failed: {message}"
        let prefix_str = self
            .builder
            .build_global_string_ptr("Assertion failed: ", "assert_prefix")?;
        let _ = self.builder.build_call(
            printf_func,
            &[prefix_str.as_pointer_value().into()],
            "printf_assert_prefix",
        );

        // Print the message
        let message = self.generate_expression(&arguments[1])?;
        if let BasicValueEnum::PointerValue(msg_ptr) = message {
            let format_str = self
                .builder
                .build_global_string_ptr("%s\n", "assert_format")?;
            let _ = self.builder.build_call(
                printf_func,
                &[format_str.as_pointer_value().into(), msg_ptr.into()],
                "printf_assert_msg",
            );
        }

        // Call exit(1)
        let exit_code = self.context.i32_type().const_int(1, false);
        let _ = self
            .builder
            .build_call(exit_func, &[exit_code.into()], "exit_call");
        let _ = self.builder.build_unreachable();

        // Generate pass block (assertion passed, continue execution)
        self.builder.position_at_end(pass_block);

        Ok(self.context.i32_type().const_int(0, false).into())
    }

    pub(super) fn generate_assert_panics_call(
        &mut self,
        test_expr: &Expression,
        message_expr: &Expression,
        location: crate::error::Location,
    ) -> Result<BasicValueEnum<'ctx>> {
        let func = self.current_function.ok_or_else(|| {
            CompilerError::internal("assert_panics can only be used inside a function")
        })?;

        let panic_after_block = self
            .context
            .append_basic_block(func, "assert_panics_caught");
        let continue_block = self
            .context
            .append_basic_block(func, "assert_panics_continue");

        let recover_stmt = stmt::RecoverStmt {
            error_var: "__assert_panics_err".to_string(),
            arms: vec![stmt::RecoverArm {
                pattern: Pattern::Wildcard,
                guard: None,
                body: Statement::Block(stmt::BlockStmt {
                    statements: vec![],
                    location,
                }),
                location,
            }],
            location,
        };

        self.recover_stack.push(recover_stmt);
        self.recover_after_blocks.push(panic_after_block);

        // Fast-path: inline zero-arg function literal bodies so panic stays in the same
        // function and can be caught by the synthetic recover handler above.
        if let Expression::FunctionLiteral(func_lit) = test_expr {
            if let Some(lambda) = &func_lit.lambda {
                let _ = self.generate_expression(&lambda.body)?;
            } else {
                // Fallback: treat as a normal call
                let inner_call = CallExpr {
                    callee: Box::new(test_expr.clone()),
                    type_args: vec![],
                    arguments: vec![],
                    resolved: None,
                    location,
                };
                let call_expr = Expression::Call(inner_call);
                let _ = self.generate_expression(&call_expr)?;
            }
        } else {
            let inner_call = CallExpr {
                callee: Box::new(test_expr.clone()),
                type_args: vec![],
                arguments: vec![],
                resolved: None,
                location,
            };
            let call_expr = Expression::Call(inner_call);
            let _ = self.generate_expression(&call_expr)?;
        }

        let _ = self.recover_stack.pop();
        let _ = self.recover_after_blocks.pop();

        let mut assert_args = Vec::with_capacity(2);
        assert_args.push(Expression::Literal(Literal::Boolean(false)));
        assert_args.push(message_expr.clone());
        let _ = self.generate_assert_call(&assert_args)?;
        let _ = self.builder.build_unconditional_branch(continue_block)?;

        self.builder.position_at_end(panic_after_block);
        self.builder.build_unconditional_branch(continue_block)?;

        self.builder.position_at_end(continue_block);
        Ok(self.context.i32_type().const_int(0, false).into())
    }
}
